// Kony


#include "Actor/BasePointCollection.h"

#include "AbilitySystem/BaseAbilitySystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"


/*
 * 点集合 演员类，用于创建一些生成点 用于群体法术在对应点生成粒子效果
 */
ABasePointCollection::ABasePointCollection()
{
	PrimaryActorTick.bCanEverTick = false;
	
	//创建点集合场景组件
	Pt_0 = CreateDefaultSubobject<USceneComponent>("Pt_0");
	ImmutablePts.Add(Pt_0);
	SetRootComponent(Pt_0);

	Pt_1 = CreateDefaultSubobject<USceneComponent>("Pt_1");
	ImmutablePts.Add(Pt_1);
	Pt_1->SetupAttachment(GetRootComponent());

	Pt_2 = CreateDefaultSubobject<USceneComponent>("Pt_2");
	ImmutablePts.Add(Pt_2);
	Pt_2->SetupAttachment(GetRootComponent());

	Pt_3 = CreateDefaultSubobject<USceneComponent>("Pt_3");
	ImmutablePts.Add(Pt_3);
	Pt_3->SetupAttachment(GetRootComponent());

	Pt_4 = CreateDefaultSubobject<USceneComponent>("Pt_4");
	ImmutablePts.Add(Pt_4);
	Pt_4->SetupAttachment(GetRootComponent());

	Pt_5 = CreateDefaultSubobject<USceneComponent>("Pt_5");
	ImmutablePts.Add(Pt_5);
	Pt_5->SetupAttachment(GetRootComponent());

	Pt_6 = CreateDefaultSubobject<USceneComponent>("Pt_6");
	ImmutablePts.Add(Pt_6);
	Pt_6->SetupAttachment(GetRootComponent());

	Pt_7 = CreateDefaultSubobject<USceneComponent>("Pt_7");
	ImmutablePts.Add(Pt_7);
	Pt_7->SetupAttachment(GetRootComponent());

	Pt_8 = CreateDefaultSubobject<USceneComponent>("Pt_8");
	ImmutablePts.Add(Pt_8);
	Pt_8->SetupAttachment(GetRootComponent());

	Pt_9 = CreateDefaultSubobject<USceneComponent>("Pt_9");
	ImmutablePts.Add(Pt_9);
	Pt_9->SetupAttachment(GetRootComponent());

	Pt_10 = CreateDefaultSubobject<USceneComponent>("Pt_10");
	ImmutablePts.Add(Pt_10);
	Pt_10->SetupAttachment(GetRootComponent());


	// 设置环形布局 规整布局 
	// float Radius = 200.f;
	// int32 NumPoints = 10;
	// for (int32 i = 1; i <= NumPoints; ++i)
	// {
	// 	float AngleRad = FMath::DegreesToRadians((360.f / NumPoints) * (i - 1));
	// 	ImmutablePts[i]->SetRelativeLocation(FVector(FMath::Cos(AngleRad) * Radius, FMath::Sin(AngleRad) * Radius, 0.f));
	// }
	
	// 设置环形布局（带随机偏移）
	// float Radius = 200.f;
	// int32 NumPoints = 10;
	// float MaxOffset = 20.f; // 偏移最大值，可以调节大小
	// for (int32 i = 1; i <= NumPoints; ++i)
	// {
	// 	float AngleRad = FMath::DegreesToRadians((360.f / NumPoints) * (i - 1));
 //    
	// 	// 均匀圆坐标
	// 	float BaseX = FMath::Cos(AngleRad) * Radius;
	// 	float BaseY = FMath::Sin(AngleRad) * Radius;
	//
	// 	// 随机浮动
	// 	float OffsetX = FMath::RandRange(-MaxOffset, MaxOffset);
	// 	float OffsetY = FMath::RandRange(-MaxOffset, MaxOffset);
	//
	// 	ImmutablePts[i]->SetRelativeLocation(FVector(BaseX + OffsetX, BaseY + OffsetY, 0.f));
	// }
	
}

void ABasePointCollection::BeginPlay()
{
	Super::BeginPlay();

	
}

void ABasePointCollection::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}
// 获取地面点集合的函数，根据指定位置、点数量和偏航角返回场景组件数组
// @param GroundLocation 地面位置，用于确定点集合的中心位置
// @param NumPoints 需要获取距离中心最近的点数量
// @param YawOverride 偏航角覆盖值，用于调整点的朝向，默认为0.f
TArray<USceneComponent*> ABasePointCollection::GetGroundPoints(const FVector& GroundLocation, int32 NumPoints, float YawOverride)
{
	checkf(ImmutablePts.Num() >= NumPoints, TEXT("尝试访问超出点集合范围的不可变集合"));
	TArray<USceneComponent*> ArrayCopy;//数组副本
	for (USceneComponent* Pt: ImmutablePts)
	{
		if (ArrayCopy.Num() >= NumPoints) return ArrayCopy; //如果超出需要的点数 直接返回
		//根据我们设置的Pt_0点旋转
		if (Pt != Pt_0)
		{
			//计算当前点到基准点 Pt_0 的向量（相对位置）
			FVector ToPoint = Pt->GetComponentLocation() - Pt_0->GetComponentLocation();
			//将这个相对向量绕着世界的 UpVector (Z轴) 旋转 YawOverride 角度
			ToPoint = ToPoint.RotateAngleAxis(YawOverride, FVector::UpVector);
			//把点的位置更新到新的旋转后位置（保持以 Pt_0 为中心）
			Pt->SetWorldLocation(Pt_0->GetComponentLocation() + ToPoint);
		}
		//定义一个“升高位置”：保持点的 X/Y 坐标不变，Z 坐标固定在地面高度 + 500
		const FVector RaisedLocation = FVector(Pt->GetComponentLocation().X, Pt->GetComponentLocation().Y, GroundLocation.Z + 500.f);
		//定义一个“降低位置”：保持点的 X/Y 坐标不变，Z 坐标固定在地面高度 - 500
		const FVector LoweredLocation = FVector(Pt->GetComponentLocation().X, Pt->GetComponentLocation().Y, GroundLocation.Z - 500.f);
		//进行线性追踪
		FHitResult HitResult;
		TArray<AActor*> IgnoreActors;//返回的范围内演员
		//获取半径范围内活着的角色
		UBaseAbilitySystemLibrary::GetLivePlayersWithinRadius(this,IgnoreActors, TArray<AActor*>(), 1500.f, GetActorLocation());
		//设置射线检测的查询参数
		FCollisionQueryParams QueryParams;
		//把要忽略的角色加入查询参数，避免射线命中他们
		QueryParams.AddIgnoredActors(IgnoreActors);
		//从 RaisedLocation → LoweredLocation 发射一条射线
		//使用 "BlockAll" 碰撞通道配置
		//命中结果存储到 HitResult
		GetWorld()->LineTraceSingleByProfile(HitResult, RaisedLocation, LoweredLocation, FName("BlockAll"), QueryParams);

		//创建一个调整后的位置：保持点的 X/Y 坐标不变，但把 Z 坐标设置为射线命中位置的 Z 值（即地面高度）
		const FVector AdjustedLocation = FVector(Pt->GetComponentLocation().X,Pt->GetComponentLocation().Y, HitResult.ImpactPoint.Z);
		//更新点的位置到地面高度，使点“贴合”到检测到的地面上
		Pt->SetWorldLocation(AdjustedLocation);
		//根据射线命中的表面法线，计算一个旋转，使点的Z轴朝向法线方向
		//这样点就会自动跟随地面坡度对齐，而不是永远竖直向上
		Pt->SetWorldRotation(UKismetMathLibrary::MakeRotFromZ(HitResult.ImpactNormal));

		ArrayCopy.Add(Pt);
	}
	return ArrayCopy;
}

